package com.h5ve.system.service.impl;

import cn.dev33.satoken.secure.BCrypt;
import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.h5ve.base.constant.CommonConstants;
import com.h5ve.base.exception.BaseException;
import com.h5ve.data.annotation.DataFilter;
import com.h5ve.data.vo.WarmFlowInteractiveTypeVo;
import com.h5ve.security.entity.H5veUser;
import com.h5ve.security.util.SecurityUtil;
import com.h5ve.system.dto.LoginDto;
import com.h5ve.system.entity.Dept;
import com.h5ve.system.entity.Role;
import com.h5ve.system.entity.User;
import com.h5ve.system.entity.UserRole;
import com.h5ve.system.mapper.UserMapper;
import com.h5ve.system.service.*;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.concurrent.TimeUnit;

/**
 * <p>
 * 用户信息表 服务实现类
 * </p>
 *
 * @author h5ve
 * @since 2019-01-30
 */
@Service
@RequiredArgsConstructor
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {

    @Value("${h5ve.redisSwitch}")
    private Boolean redisSwitch;

    @Value("${user.password.maxRetryCount}")
    private int maxRetryCount;

    private final ConfigService configService;
    private final RoleService roleService;
    private final MenuService menuService;
    private final UserRoleService userRoleService;
    private final DeptService deptService;
    private final RedisTemplate redisTemplate;

    @Override
    public String login(LoginDto loginDto) {
        // 验证码校验
        String redisKey = CommonConstants.CAPTCHA_PREFIX + loginDto.getRealKey();
        Object obj = redisTemplate.opsForValue().get(redisKey);
        if (obj == null || (obj != null && !StrUtil.equals(obj.toString().toLowerCase(), loginDto.getCode().toLowerCase()))) {
            throw new BaseException("sys.captcha.notexists", loginDto.getCode());
        }
        redisTemplate.delete(redisKey);
        // Todo 密码错误尝试
        User user = baseMapper.selectOne(new QueryWrapper<User>().eq("user_name", loginDto.getUserName()));
        if (StrUtil.isEmptyIfStr(user)) {
            throw new BaseException("sys.account.notexists", loginDto.getUserName());
        } else if ("1".equals(user.getStatus())) {
            throw new BaseException("sys.account.locked", loginDto.getUserName());
        }
        //普通用户不可登录
//        if ("03".equals(user.getType())) {
//            throw new BaseException("sys.account.notlogin", loginDto.getUserName());
//        }
        int retryTimes = 0;
        Object petObj = redisTemplate.opsForValue().get(CommonConstants.PWD_ERR_TIMES + loginDto.getUserName());
        if (petObj != null) {
            retryTimes = Integer.parseInt(petObj.toString());
        }
        if (retryTimes >= Integer.valueOf(maxRetryCount).intValue()) {
            throw new BaseException("密码输入错误过多，账号锁定5分钟");
        }
        //密码校验
        if (!BCrypt.checkpw(loginDto.getPassword(), user.getPassword())) {
            retryTimes += 1;
            redisTemplate.opsForValue().set(CommonConstants.PWD_ERR_TIMES + loginDto.getUserName(), retryTimes + "");
            redisTemplate.expire(CommonConstants.PWD_ERR_TIMES + loginDto.getUserName(), 5, TimeUnit.MINUTES);
            throw new BaseException("sys.account.notexists", loginDto.getUserName());
        } else {
            redisTemplate.delete(CommonConstants.PWD_ERR_TIMES + loginDto.getUserName());
        }
        H5veUser h5veUser = new H5veUser();
        BeanUtils.copyProperties(user, h5veUser);
        List<Role> roleList = roleService.selectMyRolesByUserId(h5veUser.getId());
        Set<String> roles = new HashSet<>();
        Set<String> permissions = new HashSet<>();
        roleList.forEach(role -> {
            roles.add(CommonConstants.ROLE + role.getId());
            if (role.getId() == 1l) {
                permissions.add("*_*");
            } else {
                List<String> perms = menuService.selectPermsByRoleId(role.getId());
                if (perms != null && perms.size() > 0) {
                    permissions.addAll(perms);
                }
            }
        });
        h5veUser.setRoles(roles);
        h5veUser.setPermissions(permissions);
        SecurityUtil.setUser(loginDto.getUserName(), h5veUser);
        return StpUtil.getTokenValue();
    }

    @Override
    public String getValueByKey(String key) {
        String value = "";
        //redis缓存
        if (redisSwitch) {
            Object valStr = redisTemplate.opsForValue().get("UserName:" + key);
            if (!StrUtil.isEmptyIfStr(valStr)) {
                value = valStr.toString();
            } else {
                User user = baseMapper.selectOne(new QueryWrapper<User>().eq("user_name", key));
                if (user != null) {
                    value = user.getNickName();
                    redisTemplate.opsForValue().set("UserName:" + key, user.getNickName());
                }
            }
        } else {
            User user = baseMapper.selectOne(new QueryWrapper<User>().eq("user_name", key));
            if (user != null) {
                value = user.getNickName();
            }
        }
        return value;
    }

    @Override
    @Transactional
    public int saveUser(User user) {
        if (StrUtil.isEmptyIfStr(user.getId())) {
            // 新增用户信息
            int rows = baseMapper.insert(user);
            // 新增用户与角色管理
            addUserRole(user);
            return rows;
        } else {
            // 删除用户与角色关联
            userRoleService.remove(new QueryWrapper<UserRole>().eq("user_id", user.getId()));
            // 新增用户与角色管理
            addUserRole(user);
            user.setPassword(null);
            return baseMapper.updateById(user);
        }
    }

    /**
     * 新增用户角色信息
     *
     * @param user 用户对象
     */
    public void addUserRole(User user) {
        Long[] roles = user.getRoles();
        if (roles != null) {
            // 新增用户与角色管理
            for (Long roleId : roles) {
                UserRole ur = new UserRole();
                ur.setUserId(user.getId());
                ur.setRoleId(roleId);
                userRoleService.save(ur);
            }
        }
    }

    /**
     * 导入用户数据
     *
     * @param userList        用户数据列表
     * @param isUpdateSupport 是否更新支持，如果已存在，则进行更新数据
     * @return 结果
     */
    @Override
    public String importUser(List<User> userList, Boolean isUpdateSupport) {
        if (userList == null || userList.size() == 0) {
            throw new BaseException("导入用户数据不能为空！");
        }
        int successNum = 0;
        int failureNum = 0;
        StringBuilder successMsg = new StringBuilder();
        StringBuilder failureMsg = new StringBuilder();
        String password = configService.getValueByKey("user.initPassword");
        for (User user : userList) {
            try {
                // 验证是否存在这个用户
                User u = baseMapper.selectOne(new QueryWrapper<User>().eq("user_name", user.getUserName()));
                if (u == null) {
                    user.setPassword(BCrypt.hashpw(password));
                    if (StrUtil.isNotBlank(user.getDeptName())) {
                        Dept dept = deptService.getOne(new QueryWrapper<Dept>().eq("name", user.getDeptName()));
                        if (dept != null) {
                            user.setDeptId(dept.getDeptId());
                            user.setDeptName(dept.getName());
                        }
                    }
                    baseMapper.insert(user);
                    successNum++;
                    successMsg.append("<br/>" + successNum + "、账号 " + user.getUserName() + " 导入成功");
                } else if (isUpdateSupport) {
                    this.updateById(user);
                    successNum++;
                    successMsg.append("<br/>" + successNum + "、账号 " + user.getUserName() + " 更新成功");
                } else {
                    failureNum++;
                    failureMsg.append("<br/>" + failureNum + "、账号 " + user.getUserName() + " 已存在");
                }
            } catch (Exception e) {
                failureNum++;
                String msg = "<br/>" + failureNum + "、账号 " + user.getUserName() + " 导入失败：";
                failureMsg.append(msg + e.getMessage());
            }
        }
        if (failureNum > 0) {
            failureMsg.insert(0, "很抱歉，导入失败！共 " + failureNum + " 条数据格式不正确，错误如下：");
            throw new BaseException(failureMsg.toString());
        } else {
            successMsg.insert(0, "恭喜您，数据已全部导入成功！共 " + successNum + " 条，数据如下：");
        }
        return successMsg.toString();
    }

    @Override
    public User getUserByPhone(String phone) {
        return baseMapper.getByPhone(phone);
    }

    @Override
    public User getUserByUserName(String userName) {
        return baseMapper.getByUserName(userName);
    }

    @Override
    public String getNameBy(String account) {
        String value = "";
        //redis缓存
        if (redisSwitch) {
            Object valStr = redisTemplate.opsForValue().get("account:" + account);
            if (!StrUtil.isEmptyIfStr(valStr)) {
                value = valStr.toString();
            } else {
                User user = baseMapper.selectOne(new QueryWrapper<User>().eq("user_name", account));
                if (user != null) {
                    value = user.getNickName();
                    redisTemplate.opsForValue().set("account:" + account, user.getNickName());
                }
            }
        } else {
            User user = baseMapper.selectOne(new QueryWrapper<User>().eq("user_name", account));
            if (user != null) {
                value = user.getNickName();
            }
        }
        return value;
    }

    @Override
    public Page<User> selectAllocatedList(Page<User> page, User user) {
        return page.setRecords(baseMapper.selectAllocatedList(page, user));
    }

    @Override
    public Page<User> selectUnallocatedList(Page<User> page, User user) {
        return page.setRecords(baseMapper.selectUnallocatedList(page, user));
    }

    /**
     * 查询不包含输入的所有用户
     *
     * @param warmFlowInteractiveTypeVo 输入用户编号集合
     * @return 用户列表
     */
    @DataFilter()
    @Override
    public List<User> selectNotUserList(WarmFlowInteractiveTypeVo warmFlowInteractiveTypeVo) {
        return baseMapper.selectNotUserIds(warmFlowInteractiveTypeVo);
    }

    /**
     * 查询包含输入的所有用户
     *
     * @param warmFlowInteractiveTypeVo 输入用户编号集合
     * @return 用户列表
     */
    @Override
    public List<User> selectUserList(WarmFlowInteractiveTypeVo warmFlowInteractiveTypeVo) {
        return baseMapper.selectUserIds(warmFlowInteractiveTypeVo);
    }
}
